
using System;
using System.Collections.Generic;
using ScrewTurn.Wiki.PluginFramework;

namespace ScrewTurn.Wiki {

	/// <summary>
	/// Manages Page Editing collisions.
	/// </summary>
	public class Collisions {

		private static Collisions instance;

		/// <summary>
		/// Gets or sets the singleton instance of the Collision object.
		/// </summary>
		public static Collisions Instance {
			get { return instance; }
			set { instance = value; }
		}

		public const int RefreshInterval = 20;

		private List<EditingSession> sessions;

		/// <summary>
		/// Initializes a new instance of the <b>Collisions</b> class.
		/// </summary>
		public Collisions() {
			sessions = new List<EditingSession>();
		}

		/// <summary>
		/// Adds or updates an editing session.
		/// </summary>
		/// <param name="page">The edited Page.</param>
		/// <param name="user">The User who is editing the Page.</param>
		public void Renew(PageInfo page, string user) {
			lock(sessions) {
				bool found = false;
				for(int i = 0; i < sessions.Count; i++) {
					if(sessions[i].Page == page && sessions[i].User.Equals(user)) {
						sessions[i].Renew();
						found = true;
						break;
					}
				}
				if(!found) sessions.Add(new EditingSession(page, user));
			}
		}

		/// <summary>
		/// Cancels an editing session.
		/// </summary>
		/// <param name="page">The Page.</param>
		/// <param name="user">The User.</param>
		public void Cancel(PageInfo page, string user) {
			for(int i = 0; i < sessions.Count; i++) {
				if(sessions[i].Page == page && sessions[i].User.Equals(user)) {
					sessions.Remove(sessions[i]);
					break;
				}
			}
		}

		/// <summary>
		/// Finds whether a Page is being edited by a different user.
		/// </summary>
		/// <param name="page">The Page.</param>
		/// <param name="currentUser">The User who is requesting the status of the Page.</param>
		/// <returns>True if the Page is being edited by another User.</returns>
		public bool IsEdited(PageInfo page, string currentUser) {
			// Last Contact should be within now and now minus "one minute and a delta"
			DateTime limit = DateTime.Now.AddSeconds(-(RefreshInterval + 5));
			lock(sessions) {
				for(int i = 0; i < sessions.Count; i++) {
					if(sessions[i].Page == page && !sessions[i].User.Equals(currentUser)) {
						if(sessions[i].LastContact.CompareTo(limit) >= 0) {
							// Page is being edited
							return true;
						}
						else {
							// Lost contact
							sessions.Remove(sessions[i]);
							return false;
						}
					}
				}
			}
			return false;
		}

		/// <summary>
		/// Gets the username of the user who's editing a page.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <returns>The username.</returns>
		public string WhosEditing(PageInfo page) {
			lock(sessions) {
				foreach(EditingSession s in sessions) {
					if(s.Page == page) return s.User;
				}
			}
			return "";
		}

		/// <summary>
		/// Gets the list of Pages that are being edited.
		/// </summary>
		public string[] EditedPages {
			get {
				List<string> pages = new List<string>();
				lock(sessions) {
					DateTime limit = DateTime.Now.AddSeconds(-(RefreshInterval + 5));
					for(int i = 0; i < sessions.Count; i++) {
						if(sessions[i].LastContact.CompareTo(limit) >= 0)
							pages.Add(sessions[i].Page.Name + " (" + sessions[i].User + ")");
					}
				}
				return pages.ToArray();
			}
		}

	}

	/// <summary>
	/// Represents an Editing Session.
	/// </summary>
	public class EditingSession {

		private PageInfo page;
		private string user;
		private DateTime lastContact;

		/// <summary>
		/// Initializes a new instance of the <b>EditingSession</b> class.
		/// </summary>
		/// <param name="page">The edited Page.</param>
		/// <param name="user">The User who is editing the Page.</param>
		public EditingSession(PageInfo page, string user) {
			this.page = page;
			this.user = user;
			lastContact = DateTime.Now;
		}

		/// <summary>
		/// Gets the edited Page.
		/// </summary>
		public PageInfo Page {
			get { return page; }
		}

		/// <summary>
		/// Gets the User.
		/// </summary>
		public string User {
			get { return user; }
		}

		/// <summary>
		/// Sets the Last Contact to now.
		/// </summary>
		public void Renew() {
			lastContact = DateTime.Now;
		}

		/// <summary>
		/// Gets the Last Contact Date/Time.
		/// </summary>
		public DateTime LastContact {
			get { return lastContact; }
		}

	}

}
